#include "reg51.h"

#define ADDR0 P1_0
#define ADDR1 P1_1
#define ADDR2 P1_2
#define ADDR3 P1_3
#define ENLED P1_4

//用数组来存储数码管的真值表，数组将在下一章详细介绍
__code unsigned char LedChar[] = {
        0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
        0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};

// 数码管显示缓冲区
unsigned char display[6] = {
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};

// 定时器 T0 中断次数记录
unsigned int cnt = 0;

int main() {
    ENLED = 0;  // 使能 74HC138
    ADDR3 = 1;

    TMOD = 0x01;// T0 模式 1
    TH0 = 0xFC; // 定时 1ms
    TL0 = 0x66;
    TR0 = 1;    // 开始计数

    EA = 1;     // 中断总开关使能
    ET0 = 1;    // 使能 T0 定时器

    unsigned long second = 0;   // 秒数

    while (1) {
        if (cnt >= 1000) {
            // 1 秒定时
            cnt = 0;
            second++;
            display[0] = LedChar[second % 10];
            display[1] = LedChar[second / 10 % 10];
            display[2] = LedChar[second / 100 % 10];
            display[3] = LedChar[second / 1000 % 10];
            display[4] = LedChar[second / 10000 % 10];
            display[5] = LedChar[second / 100000 % 10];
        }
    }
}

/**
 * 定时器 T0 中断服务函数
 */
void InterruptTimer0() __interrupt(1) {
    static unsigned char i = 0;

    // TF0 = 0;     // 自动复位
    TH0 = 0xFC;     // 定时 1ms
    TL0 = 0x66;

    cnt++;          // 中断次数加 1
    P0 = 0xFF;      // 显示消隐
    i = i >= 6 ? 0 : i; // 修正索引值
    P1 = P1 & 0xF8 | i; // 清空 P1 的低 3 位，然后设置为 i 值
    P0 = display[i++];  // 显示
}
